home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Trading on the Edge
/
Trading On The Edge - CD-ROM Toolkit (Wayzata Technology)(2031)(1994).bin
/
pc
/
shared
/
azte_pro
/
control.c
next >
Wrap
C/C++ Source or Header
|
1993-06-11
|
38KB
|
1,821 lines
/* 10/5/89.
* Control routines for a Double Oral Auction player program
* C version. R.G. Palmer, Jan-Mar 1989.
*
* *** See comments in skeleton.c, define.h, and README for details. ***
*
* You must customize define.h before compiling, but should not need
* to change this file at all.
*
* Note: this version has some experimental code for running on a PC talking
* (via the serial port) to DANI on a mainframe etc. But it doesn't yet work.
* It should have no effect unless you try to use PIPEBASED on a PC.
*/
#include "define.h"
#ifdef BSD43
#define UNIX 1
#define RAND_MAX 2147483647
#endif
#ifdef SUN3
#define UNIX 1
#define RAND_MAX 2147483647
char * sprintf(); /* for lint */
#endif
#ifdef SUN4
#define UNIX 1
#define RAND_MAX 2147483647
char * sprintf(); /* for lint */
#endif
#ifdef CRAY
#define UNIX 1
#define RAND_MAX 32767
#endif
#ifdef IRIS
#define UNIX 1
#define RAND_MAX 32767
#endif
#ifdef TURBOC
#define MSDOS 1
#define ANSI 1
#endif
#ifdef QUICKC
#define MSDOS 1
#define ANSI 1
#endif
#ifdef VMS
#define ANSI_OR_VMS 1
#define RAND_MAX 2147483647
#define GOODEXIT 1
#define WARNEXIT 0
#define BADEXIT 2
#ifdef INETBASED
#define NETRW 1
#endif
#else
#define GOODEXIT 0
#define WARNEXIT 1
#define BADEXIT 2
#endif
#ifdef THINKC3
#define THINKC 1
#define RAND_MAX 32767
#define TZHOURS 5
#else
#define TZHOURS 0
#endif
#ifdef THINKC4
#define THINKC 1
#define ANSI 1
#endif
#ifdef THINKC
#define ALWAYSDELIN 1
#ifdef INETBASED
<<Inet-based not possible on a Mac>>
#endif
#endif
#ifdef ANSI
#define ANSI_OR_VMS 1
#endif
#ifdef ANSI_OR_VMS
#define REMOVE remove
#else
#define REMOVE unlink
#endif
#ifdef MSDOS
#ifdef INETBASED
<<Inet-based not possible on a PC>>
#endif
#endif
#ifdef NETRW
#define READ netread
#define WRITE netwrite
#else
#define READ read
#define WRITE write
#endif
/* includes */
#include <stdio.h>
#include <pwd.h>
#ifdef THINKC3
#include <strings.h>
#include <unix.h>
#else
#include <strings.h>
#include <time.h>
#endif
#ifdef THINKC4
#include <console.h>
#endif
#ifdef ANSI
#include <stddef.h>
#ifndef NO_STDLIB_H
#include <stdlib.h>
#endif
#endif
#ifdef MSDOS
#include <sys\types.h>
#else
#ifdef VMS
#ifdef INETBASED
#include <sys/types.h>
#else
#include types
#endif
#else
#ifdef THINKC3
#include <types.h>
#else
#ifndef ANSI
#include <sys/types.h>
#endif
#endif
#endif
#endif
#ifdef INETBASED
#include <sys/socket.h> /* for SOCK_... and AF_... constants */
#include <netinet/in.h> /* for struct sockaddr_in, htons() */
#include <netdb.h> /* for hostent, gethostbyname... */
#include <errno.h>
#endif
/* Various maxima. Note that these constants are also defined in
* skeleton.c and human.c, but may have smaller values there if the
* user wishes to limit array sizes. The values here should not
* need to be changed.
*/
#define MAXPLAYERS 20 /* maximum of each, MUST BE EVEN */
#define MAXROUNDS 20
#define MAXPERIODS 5
#define MAXTIMES 400
#define MAXTOKENS 4 /* MUST BE EVEN */
#define MAXFILENAME 20
/* Global variables (see comments in skeleton) */
int nplayers = 0;
int nbuyers = 0;
int nsellers = 0;
int bnumber[MAXPLAYERS+1];
int snumber[MAXPLAYERS+1];
int nrounds = 0;
int nperiods = 0;
int ntimes = 0;
int minprice = 0;
int maxprice = 8000;
int gameid = 0;
int gametype = 0;
int r = 0;
int p = 0;
int t = 0;
int cbid = 0;
int coffer = 0;
int bidder = 0;
int offerer = 0;
int nbids = 0;
int noffers = 0;
int bids[MAXPLAYERS+1];
int offers[MAXPLAYERS+1];
int bstype = 0;
int price = 0;
int buyer = 0;
int seller = 0;
int btrades[MAXPLAYERS+1];
int strades[MAXPLAYERS+1];
int ntrades = 0;
int prices[MAXPLAYERS*MAXTOKENS+1];
int lasttime = 0;
int id = 0;
int role = 0;
int timeout = 0;
int ntokens = 0;
int token[MAXTOKENS+1];
int mytrades = 0;
int mylasttime = 0;
int pprofit = 0;
int rprofit = 0;
int gprofit = 0;
int nobidoff = 0;
int bo = 0;
int nobuysell = 0;
int bs = 0;
int late = 0;
int tradelist[MAXPERIODS+1];
int profitlist[MAXPERIODS+1];
int efficiency = 0; /* doesn't need to be saved -- after END only */
int noblock = 0; /* internal variable, must be saved if FILEBASED */
extern int hmtype; /* 1 for human, 2 for machine */
/* newvars */
int havegametype;
float payment_rate, payment_base;
int clearingrule = 0;
/* Declaration of all routines */
/* External -- must be in user's part */
extern void gbegin(),gend(),rbegin(),rend();
extern void pbegin(),pend(),boend(),bsend();
extern void exp_value();
extern int bid(),offer(),buy(),sell();
extern void getparams();
extern void setnoblock(),resetterm();
extern void rantok_main();
extern void intro_chart();
#ifdef INETBASED
extern int getrole();
extern void getpname();
#endif
#ifdef FILEBASED
extern void savedata(),retrievedata();
#endif
/* Internal */
static void init1(),init2(),round(),endround(),period(),endperiod();
static void bidoff(),boresult(),buysell(),bsresult(),gameend(),killed();
static void initvars(),clearbo(),getmess(),expect(),sendmess();
static void stripcopy(),randset(),adios();
double drand();
void error();
/* new routines */
void header();
void get_gamedata();
void get_gamehist();
void get_players();
static void sleep();
int sock_gets();
void menu();
void print_menu();
void show_payment_rates();
void show_clearingrule();
void show_descriptions();
void show_players();
void show_gamehist();
void display_file();
int line_count();
void waitkey();
#ifdef FILEBASED
static void filesetup();
void readarray(),writearray();
#endif
#ifdef PIPEBASED
static void pipesetup();
#endif
#ifdef INETBASED
int inetsetup();
#endif
#ifdef DISPLAY
void twolinehead(),showcurrent(),showprices(),nl();
static void nput();
#endif
/* names local to this file (no need to save in FILEBASED) */
static int mtype = 0;
static int mpar1 = 0;
static int mpar2 = 0;
static char progname[MAXFILENAME-4];
#ifdef THINKC4
static char pprogname[MAXFILENAME-4]; /* Pascal copy */
#endif
int waitforreturn = 0; /* for THINKC: forces wait for CR on exit if set */
#ifdef FILEBASED
static char inname[MAXFILENAME];
static char outname[MAXFILENAME];
static FILE *outfile = NULL;
static FILE *infile = NULL;
FILE *savefile = NULL;
#else
#ifndef MSDOS
int outfd = -1;
int infd = -1;
#else
/* experimental code */
char auxbuf[100];
#endif
#endif
#ifdef DISPLAY
#define DSPLY 1
#define BUYCHAR '<'
#define SELLCHAR '>'
#define DISPLAY_OR_INET 1
#else
#define DSPLY 0
#ifdef INETBASED
#define DISPLAY_OR_INET 1
#endif
#endif
#define EOS '\0'
#define BELL 07
#define RINT register int
/* code table for messages */
#define ACCEPT 1
#define BID 2
#define BIDOFF 3
#define BODISP 4
#define BSDISP 5
#define BUY 6
#define BUYERS 29
#define BUYSELL 7
#define CBID 8
#define COFFER 9
#define END 10
#define GAME 11
#define KILLED 98
#define LENGTH 12
#define LIMITS 13
#define NONE 14
#define NUMBER 15
#define OFFER 16
#define PERIOD 17
#define PLAYER 18
#define PRICES 19
#define QUIT 99
#define READY 20
#define REFUSE 21
#define ROLE 22
#define ROUND 27
#define SELL 23
#define SELLERS 30
#define TEST 31
#define TOKENS 28
#define TRADE 24
#define TRADERS 25
#define TYPE 26
main(argc,argv)
int argc;
char *argv[];
{
/* get program name, stripped of directories and extension */
#ifdef PROGNAME
stripcopy(progname,PROGNAME,MAXFILENAME-5);
#else
#ifdef THINKC
{
char apName[256];
int apRefNum;
Handle apParam;
GetAppParms(apName,&apRefNum,&apParam);
PtoCstr(apName);
stripcopy(progname,apName,MAXFILENAME-5);
#ifdef THINKC3
Click_On(FALSE);
#else
console_options.top = 60;
console_options.nrows = 16;
strcpy(pprogname,progname);
CtoPstr(pprogname);
console_options.title = pprogname;
console_options.pause_atexit = 0;
#endif
}
#else
stripcopy(progname,argv[0],MAXFILENAME-5);
#ifdef FILEBASED
if (strcmp(argv[0],"a.out")==0)
error("*program name cannot end in .out");
#endif
#endif
#endif
/* Set up input and output file pointers (FILEBASED) or
* file descriptors (PIPEBASED or INETBASED).
*/
#ifdef PIPEBASED
#ifdef MSDOS
/* experimental code */
puts("Type your command to start dani. Use the -u option.\n");
fgets(auxbuf,100,stdin);
fputs(auxbuf,stdaux);
#else
pipesetup(argc,argv);
#endif
#endif
#ifdef FILEBASED
filesetup(argc);
#endif
#ifdef INETBASED
if (argc>=2) {
if (inetsetup(argv[1],atoi(argv[2]),DSPLY))
adios(WARNEXIT,0,0);
}
else {
if (inetsetup(NULL,0,DSPLY))
adios(WARNEXIT,0,0);
}
#endif
/* menu options */
header();
printf("\nPress Enter/Return to begin...\n");
waitkey();
menu();
/* play a game */
WRITE(outfd,"ready\n",strlen("ready\n"));
/* main loop to read a message and branch accordingly */
/* read a message */
getmess(&mtype,&mpar1,&mpar2);
#ifdef FILEBASED
/* read our saved variables if filebased unless init-1 or KILLED or TEST */
if (mtype != TYPE && mtype != KILLED && mtype != TEST) {
outfile = fopen(outname,"r+");
if (outfile == NULL) {
if (mtype != END) error("can't open .out file");
}
else {
int c;
while ((c=getc(outfile))!=EOF && c!='\n') ; /* skip old output */
savefile = outfile;
retrievedata();
rewind(outfile);
randset(); /* set up random number generator */
if (noblock)
setnoblock(); /* restore non-blocking mode if needed */
}
}
#endif
/* branch on type of (first) message */
while (1) {
switch (mtype) {
case TYPE:
init1();
break;
case NUMBER:
init2();
break;
case ROUND:
if (p>0) endperiod(); /* end of previous period */
if (r>0) endround(); /* end of previous round */
round();
break;
case PERIOD:
if (p>0) endperiod(); /* end of previous period */
period();
break;
case BIDOFF:
bidoff();
break;
case BODISP:
boresult();
break;
case BUYSELL:
buysell();
break;
case BSDISP:
bsresult();
break;
case END:
if (p>0) endperiod(); /* end of period */
if (r>0) endround(); /* end of round */
gameend(); /* end of game */
adios(GOODEXIT,1,1);
/*NOTREACHED*/
case KILLED:
killed();
/*NOTREACHED*/
case TEST:
sendmess(TEST,mpar1);
break;
default:
error("unexpected message");
}
getmess(&mtype,&mpar1,&mpar2);
}
/*NOTREACHED*/
}
static void
init1() /* initialization-1 step */
{
RINT i;
int ignore,reason;
int protocol;
int maxplayers,maxrounds,maxperiods,maxtimes,maxtokens,roles,playernumber;
#ifdef DISPLAY_OR_INET
static char unacceptable[] = " unacceptable\n";
#endif
protocol = mpar1;
/* initialize all arrays explicity */
for (i=0;i<=MAXPLAYERS;i++) {
bids[i] = 0;
offers[i] = 0;
btrades[i] = 0;
strades[i] = 0;
bnumber[i] = 0;
snumber[i] = 0;
}
for (i=0;i<=MAXTOKENS;i++)
token[i] = 0;
for (i=0;i<=MAXPLAYERS*MAXTOKENS;i++)
prices[i] = 0;
for (i=0;i<=MAXPERIODS;i++) {
tradelist[i] = 0;
profitlist[i] = 0;
}
/* get rest of initialization-1 packet */
expect(GAME,&gametype,&gameid);
expect(LENGTH,&nrounds,&ignore);
expect(LENGTH,&nperiods,&ntimes);
expect(TOKENS,&ntokens,&ignore);
expect(NUMBER,&nbuyers,&nsellers);
expect(ROLE,&role,&timeout);
/* get user's limits, acceptable roles, and playernumber */
getparams(&maxplayers,&maxrounds,&maxperiods,&maxtimes,&maxtokens,&roles,
&playernumber);
if (maxplayers > MAXPLAYERS) maxplayers = MAXPLAYERS;
if (maxrounds > MAXROUNDS) maxrounds = MAXROUNDS;
if (maxperiods > MAXPERIODS) maxperiods = MAXPERIODS;
if (maxtimes > MAXTIMES) maxtimes = MAXTIMES;
if (maxtokens > MAXTOKENS) maxtokens = MAXTOKENS;
/* see if we can play */
reason = 0;
#ifdef DISPLAY_OR_INET
if (protocol != 5) {
reason |= 1;
printf("** protocol %d%s",protocol,unacceptable);
}
if (nrounds>maxrounds) {
reason |= 4;
printf("** nrounds = %d --%s",nrounds,unacceptable);
}
if (nperiods>maxperiods) {
reason |= 8;
printf("** nperiods = %d --%s",nperiods,unacceptable);
}
if (ntimes>maxtimes) {
reason |= 16;
printf("** ntimes = %d --%s",ntimes,unacceptable);
}
if (ntokens>maxtokens) {
reason |= 32;
printf("** ntokens = %d --%s",ntokens,unacceptable);
}
if (nbuyers>maxplayers || nsellers>maxplayers) {
reason |= 64;
printf("** nbuyers = %d, nsellers = %d --%s",
nbuyers,nsellers,unacceptable);
}
if (!(role&roles)) {
reason |= 128;
printf("** monitor expects a %s\n",(role==1)?"buyer":"seller");
}
if (hmtype==1 && timeout<5) {
reason |= 256;
printf(
"** timeout = %d -- too small for human player (missing -h flag?)\n",
timeout);
}
#else
if (protocol != 5) reason |= 1;
if (nrounds>maxrounds) reason |= 4;
if (nperiods>maxperiods) reason |= 8;
if (ntimes>maxtimes) reason |= 16;
if (ntokens>maxtokens) reason |= 32;
if (nbuyers>maxplayers || nsellers>maxplayers) reason |= 64;
if (!(role&roles)) reason |= 128;
if (hmtype==1 && timeout<5) reason |= 256;
#endif
#ifdef DISPLAY
if (nbuyers+nsellers>MAXDISPLAY) {
reason |= 64;
printf("** nbuyers+nsellers = %d -- too large for DISPLAY\n",
nbuyers+nsellers);
}
#endif
/* send ACCEPT or REFUSE message */
if (reason != 0) {
#ifdef DISPLAY_OR_INET
puts("*** refused to play game ***");
#endif
sendmess(REFUSE,reason);
adios(WARNEXIT,1,0);
}
sendmess(ACCEPT,playernumber);
}
static void
init2() /* initialization-2 step */
{
RINT i;
int ignore;
#ifdef DISPLAY
#ifndef THINKC3
time_t time();
#endif
time_t timeval = time((time_t *)0) - (TZHOURS*3600);
#endif
/* initialization-2 step */
nbuyers = mpar1;
nsellers = mpar2;
for (i=1; i<=nbuyers; i+=2)
expect(BUYERS,bnumber+i,bnumber+i+1);
for (i=1; i<=nsellers; i+=2)
expect(SELLERS,snumber+i,snumber+i+1);
expect(LIMITS,&minprice,&maxprice);
expect(PLAYER,&id,&ignore);
nplayers = nbuyers+nsellers;
/* set up random number generator (uses id) */
randset();
#ifdef DISPLAY
printf("\nDA game %4d %s",gameid,ctime(&timeval));
nput('-',38);
printf("\nnrounds: %d nperiods: %d ntimes: %d price range: %d-%d\n",
nrounds,nperiods,ntimes,minprice,maxprice);
printf("gametype: %04d\n",gametype);
printf("\n%2d buyer%s ",nbuyers,nbuyers>1?"s:":": ");
for (i=1; i<=nbuyers; i++) {
if (i%6==1 && i>1) { nl(); nput(' ',12); }
printf(" B%-2d %4d",i,bnumber[i]);
}
printf("\n%2d seller%s",nsellers,nsellers>1?"s:":": ");
for (i=1; i<=nsellers; i++) {
if (i%6==1 && i>1) { nl(); nput(' ',12); }
printf(" S%-2d %4d",i,snumber[i]);
}
printf("\nYou are %s%d, otherwise known as YOU\n",
role==1?"buyer B":"seller S",id);
fflush(stdout);
waitforreturn = 1;
#endif
gbegin(); /* start of game */
sendmess(READY,id);
}
static void
round() /* round step */
{
RINT i;
r = mpar1;
ntokens = mpar2;
for (i=1; i<=ntokens; i+=2)
expect(PRICES,&token[i],&token[i+1]);
for (i=ntokens+1; i<=MAXTOKENS; i++)
token[i] = 0;
p = 0;
rprofit = 0;
initvars(); /* initialize variables */
for (i=1; i<=MAXPERIODS; i++) {
tradelist[i] = 0;
profitlist[i] = 0;
}
rbegin(); /* start of round */
sendmess(READY,id);
}
static void
endround() /* end of round */
{
#ifdef DISPLAY
RINT i;
int tradesum = 0;
nl();
nput('=',20);
printf(" End of round %d ",r);
nput('=',20);
puts("\nSummary: period trades profit");
for (i=1; i<=p; i++) {
printf(" %2d %d %4d\n",i,tradelist[i],
profitlist[i]);
tradesum += tradelist[i];
}
printf(" total %d %4d\n\n",tradesum,rprofit);
fflush(stdout);
nl();
waitforreturn = 1;
#endif
rend();
}
static void
period() /* period step */
{
r = mpar1;
p = mpar2;
initvars(); /* initialize variables */
pbegin(); /* start of period */
sendmess(READY,id);
}
static void
endperiod() /* end of period */
{
#ifdef DISPLAY
printf("\n--- end of period %d of round %-2d%c",p,r,(r>9)?' ':'-');
nput('-',47);
printf("\nYou made %d trades, making a total profit of %d in this period\n",
mytrades,pprofit);
showprices();
waitforreturn = 1;
#endif
pend();
}
static void
bidoff() /* bid-offer step */
{
int value;
t = mpar1;
nobidoff = mpar2;
#ifdef DISPLAY
nl();
twolinehead();
waitforreturn = 1;
#endif
if (role == 1) {
value = bid(); /* ask the bid routine what to do */
if (value != 0)
sendmess(BID,value);
}
else {
value = offer(); /* ask the offer routine what to do */
if (value != 0)
sendmess(OFFER,value);
}
if (value == 0)
sendmess(NONE,0);
}
static void
boresult() /* process bid-offer result packet */
{
#ifdef DISPLAY
RINT i;
char * msg;
#endif
bo = mpar1;
mytrades = mpar2;
tradelist[p] = mytrades;
if (bo == (-2)) { /* late -- minimize damage to variables */
++late;
bstype = (-1);
price = 0;
buyer = 0;
seller = 0;
nobidoff = -1;
nobuysell = -1;
}
clearbo();
while (1) {
getmess(&mtype,&mpar1,&mpar2);
if (mtype == BID) {
bids[mpar2] = mpar1;
++nbids;
}
else if (mtype == OFFER) {
offers[mpar2] = mpar1;
++noffers;
}
else
break;
}
if (mtype != CBID) error("not CBID in boresult");
cbid = mpar1;
bidder = mpar2;
expect(COFFER,&coffer,&offerer);
/* tell the user */
boend();
/* display it */
#ifdef DISPLAY
nput(' ',12);
for (i=1; i<=nbuyers; i++) {
if (i == id && role == 1)
fputs(" YOU",stdout);
else if (i>=10)
printf(" B%d",i);
else
printf(" B%d",i);
printf("/%c",btrades[i]<MAXTOKENS?'a'+btrades[i]:'-');
}
nput(' ',2);
for (i=1; i<=nsellers; i++) {
if (i == id && role == 2)
fputs(" YOU",stdout);
else if (i>=10)
printf(" S%d",i);
else
printf(" S%d",i);
printf("/%c",strades[i]<MAXTOKENS?'a'+strades[i]:'-');
}
nl();
switch (bo) {
case 2: msg = "winner "; break;
case 3: msg = "bettered "; break;
case 4: msg = "lost tie "; break;
case -1: msg = "**illegal** "; break;
case -2: msg = "**late** "; break;
default: msg = " "; break;
}
fputs(msg,stdout);
for (i=1; i<=nbuyers; i++) {
if (bids[i] > 0)
printf("%5d%c",bids[i],i==bidder?'*':' ');
else if (i == bidder)
printf("%5d#",cbid);
else
nput(' ',6);
}
nput(' ',2);
for (i=1; i<=nsellers; i++) {
if (offers[i] > 0)
printf("%5d%c",offers[i],i==offerer?'*':' ');
else if (i == offerer)
printf("%5d#",coffer);
else
nput(' ',6);
}
nl();
fflush(stdout);
waitforreturn = 1;
#endif
}
static void
buysell() /* buy-sell step */
{
int value;
t = mpar1;
nobuysell = mpar2;
if (role == 1) {
value = buy(); /* ask the buy routine what to do */
if (value != 0)
sendmess(BUY,coffer);
}
else {
value = sell(); /* ask the sell routine what to do */
if (value != 0)
sendmess(SELL,cbid);
}
if (value == 0)
sendmess(NONE,0);
}
static void
bsresult() /* process buy-sell result packet */
{
int profit;
#ifdef DISPLAY
RINT i;
char * msg;
#endif
bs = mpar1;
mytrades = mpar2;
tradelist[p] = mytrades;
if (bs == (-2)) { /* late -- minimize damage to variables */
++late;
clearbo();
nobidoff = -1;
nobuysell = -1;
}
getmess(&mtype,&mpar1,&mpar2);
if (mtype == TRADE) {
bstype = mpar1;
price = mpar2;
prices[++ntrades] = mpar2;
lasttime = t;
expect(TRADERS,&buyer,&seller);
btrades[buyer]++;
strades[seller]++;
if (id == (role==1?buyer:seller)) { /* we just made a trade */
mylasttime = t;
profit = role==1? token[mytrades]-price : price-token[mytrades];
pprofit += profit;
rprofit += profit;
gprofit += profit;
profitlist[p] = pprofit;
prices[ntrades] = -prices[ntrades]; /* to label as ours */
}
getmess(&mtype,&mpar1,&mpar2);
}
else {
bstype = 0;
price = 0;
buyer = 0;
seller = 0;
}
if (mtype != CBID) error("not CBID in bsresult");
cbid = mpar1;
bidder = mpar2;
expect(COFFER,&coffer,&offerer);
/* tell the user */
bsend();
#ifdef DISPLAY
switch (bs) {
case 2: msg = "lost toss "; break;
case 3: msg = "lost draw "; break;
case -1: msg = "**illegal** "; break;
case -2: msg = "**late** "; break;
default: msg = " "; break;
}
if (bstype>0) {
if (buyer == id && role == 1)
printf("profit:%5d",token[mytrades]-price);
else if (seller == id && role == 2)
printf("profit:%5d",price-token[mytrades]);
else
fputs(msg,stdout);
for (i=1; i<=nbuyers; i++) {
if (i == buyer)
if (bstype == 2)
printf("%5d%c",price,SELLCHAR);
else
printf(" %c ",BUYCHAR);
else
nput(' ',6);
}
nput(' ',2);
for (i=1; i<=nsellers; i++) {
if (i == seller) {
if (bstype == 1)
printf("%5d%c",price,BUYCHAR);
else
printf(" %c ",SELLCHAR);
break;
}
else
nput(' ',6);
}
nl();
}
else if (bs < 0)
puts(msg);
else
puts("no trade");
fflush(stdout);
waitforreturn = 1;
#endif
}
static void
gameend() /* end of game step */
{
efficiency = mpar2;
#ifdef DISPLAY
nl();
nput('=',30);
printf(" End of game %d ",gameid);
nput('=',31);
printf("\nTotal profit: %d",mpar1);
if (gprofit != mpar1) {
printf(" (%d accounted for)",gprofit);
gprofit = mpar1;
}
printf("\nEfficiency: %d%%\n",efficiency);
printf("\nYour total dollar winnings will be your BASE value plus\n");
printf("RATE times (efficiency - 100).\n");
fflush(stdout);
waitforreturn = 1;
#endif
gend();
}
#define MAXKILLMES 9
static char * killmsg[MAXKILLMES] = {"killed by operator","response too late",
"illegal response","bad message",".out file error","i/o failure",
"monitor error","game abandoned","killed by DANI"};
static void
killed()
{
char msg[60];
if (mpar1==1 || mpar1==9) {
strcpy(msg,"* ");
strcat(msg,killmsg[mpar1-1]);
}
else if (mpar1>0 && mpar1<=MAXKILLMES) {
strcpy(msg,"* killed by monitor -- ");
strcat(msg,killmsg[mpar1-1]);
}
else if (mpar1 == 0)
adios(WARNEXIT,1,1);
else
sprintf(msg,"*killed -- reason %d",mpar1);
error(msg);
}
/* ------------ miscellaneous support and i/o routines ---------------- */
#ifdef PIPEBASED
#ifndef MSDOS
static void
pipesetup(argc,argv)
int argc;
char *argv[];
{
/* If the command line has 2 arguments they're file descriptors for
* the pipes to the monitor. If not, we use stdin and stdout */
if (argc==3) {
if (sscanf(argv[2],"%d",&outfd) != 1)
error("output fd error");
if (sscanf(argv[1],"%d",&infd) != 1)
error("input fd error");
}
else if (hmtype==1)
error("-a option needed");
else if (argc<=1) {
infd = fileno(stdin);
outfd = fileno(stdout);
}
else
error("wrong number of arguments");
}
#endif
#endif
#ifdef FILEBASED
static void
filesetup(argc)
int argc;
{
if (argc>1)
error("too many arguments");
strcpy(inname,progname);
strcat(inname,".in");
strcpy(outname,progname);
strcat(outname,".out");
/* open input file */
infile = fopen(inname,"r");
if (infile == NULL)
error("can't open input file");
}
#endif
#ifdef INETBASED
#include "inet.c"
#endif
static void
initvars() /* Initialize everything at start of round or period */
{
RINT i;
int maxtrades;
t = 0;
cbid = 0;
coffer = 0;
bidder = 0;
offerer = 0;
bstype = 0;
price = 0;
buyer = 0;
seller = 0;
ntrades = 0;
lasttime = 0;
mytrades = 0;
mylasttime = 0;
pprofit = 0;
nobidoff = 0;
bo = 0;
nobuysell = 0;
bs = 0;
late = 0;
clearbo();
for (i=1; i<=nbuyers; i++)
btrades[i] = 0;
for (i=1; i<=nsellers; i++)
strades[i] = 0;
maxtrades = (nbuyers>nsellers?nsellers:nbuyers)*MAXTOKENS;
for (i=1; i<=maxtrades; i++)
prices[i] = 0;
}
static void
clearbo() /* clears the bids and offers */
{
RINT i;
for (i=1; i<=nbuyers; i++)
bids[i] = 0;
for (i=1; i<=nsellers; i++)
offers[i] = 0;
nbids = 0;
noffers = 0;
}
#ifdef DISPLAY
void
twolinehead()
{
printf(
"---------- round %-2d%c---------- period %d ---------- time %-2d%c",
r,r>9?' ':'-',p,t,t>9?' ':'-');
nput('-',20);
nl();
showcurrent();
}
void
showcurrent()
/*
* Shows current tokens in standard place to right of line. Also shows
* current bid and current offer at left.
*/
{
RINT i;
fputs("cbid:",stdout);
if (cbid == 0)
fputs(" (none) ",stdout);
else if (bidder==id && role == 1)
printf("%5d/YOU",cbid);
else
printf("%5d/B%-2d",cbid,bidder);
printf(" coffer:");
if (coffer == 0)
fputs(" (none) ",stdout);
else if (offerer==id && role == 2)
printf("%5d/YOU",coffer);
else
printf("%5d/S%-2d",coffer,offerer);
fputs(" ",stdout);
for (i=ntokens+1; i<=8; i++) /* right justify */
nput(' ',5);
fputs("tokens:",stdout);
for (i=1; i<=ntokens; i++)
if (i>mytrades)
printf("%5d",token[i]);
else
fputs(" -",stdout);
nl();
fflush(stdout);
}
void
showprices()
{
RINT i;
if (ntrades>0) {
fputs("Summary of trade prices",stdout);
if (mytrades>0)
fputs(" (* = yours):",stdout);
else
putchar(':');
for (i=1; i<=ntrades; i++)
if (prices[i]>0)
printf("%c%5d ",i%10==1?'\n':' ',prices[i]);
else
printf("%c%5d*",i%10==1?'\n':' ',-prices[i]);
nl();
}
else
puts("No trades");
nl();
fflush(stdout);
}
static void
nput(c,n) /* does putchar(c) n times */
int c,n;
{
RINT i;
for (i=0; i<n; i++)
putchar(c);
}
void
nl() { putchar('\n'); }
#endif
static void
getmess(ptype,ppar1,ppar2) /* receives a message */
int *ptype,*ppar1,*ppar2;
{
int n;
#ifdef FILEBASED
n = fscanf(infile,"%d%d%d",ptype,ppar1,ppar2)-3;
#else
#ifdef MSDOS
/* experimental code */
do {
if (fgets(auxbuf,100,stdaux) != NULL) {
auxbuf[99] = EOS;
if (sscanf(auxbuf,"%d%d%d",ptype,ppar1,ppar2) == 3)
n = 0;
else {
fputs(auxbuf,stdout);
auxbuf[5] = EOS;
if (strcmp(auxbuf,"Enter") == 0) {
fgets(auxbuf,100,stdin);
fputs(auxbuf,stdaux);
}
n = 1;
}
else
n = -1;
} while (n>0) ;
#else
char buf[17];
n = READ(infd,buf,16)-16;
if (n == 0) {
buf[16] = EOS;
n = sscanf(buf,"%d%d%d",ptype,ppar1,ppar2)-3;
}
#endif
#endif
if (n)
error("*connection broken");
}
static void
expect(expected,ppar1,ppar2) /* receives a message, checks type */
int expected,*ppar1,*ppar2;
{
int actual;
char emess[60];
getmess(&actual,ppar1,ppar2);
if (actual != expected) {
sprintf(emess,"protocol violation -- expected %d, actual %d",
expected,actual);
error(emess);
}
}
static void
sendmess(msgtype,par)
int msgtype,par;
/*
* Sends a message. In the FILEBASED case it opens the output file,
* writes the message, saves the data (to the same file), and quits.
* In the PIPEBASED or INETBASED case it just writes the data to the
* pipe/socket. Low-level I/O is used for ease of VMS compatability.
*/
{
#ifndef FILEBASED
/* write the message */
#ifdef VMS
char msg[13];
sprintf(msg,"%5d%5d\r\n",msgtype,par);
WRITE(outfd,msg,12);
#else
#ifdef MSDOS
fprintf(stdaux,"%5f%5d\n",msgtype,par);
#else
char msg[12];
sprintf(msg,"%5d%5d\n",msgtype,par);
WRITE(outfd,msg,11);
#endif
#endif
#else
/* close input file */
if (infile != NULL) fclose(infile);
infile = NULL;
/* open output file if not already open */
if (outfile == NULL) {
#ifdef VMS
remove(outname); /* remove previous version if any */
#endif
outfile = fopen(outname,"w");
if (outfile == NULL)
error("*can't open output file");
}
/* write the message */
fprintf(outfile,"%5d%5d\n",msgtype,par);
/* return without doing savedata if QUIT or REFUSE */
if (msgtype == QUIT || msgtype == REFUSE) return;
/* save our variables unless TEST */
if (msgtype != TEST) {
savefile = outfile;
savedata();
}
/* exit */
adios(GOODEXIT,0,0);
#endif
}
static void
stripcopy(result,input,n)
char *result,*input;
int n;
/*
* Like strncpy, but for file names. Strips any directory prefix (with /
* or \ or : or ] separators), and any extension(s) with . separator.
*/
{
char *ptr,*first;
char c;
ptr = input;
first = input;
while ((c = *ptr++) != EOS)
if (c == '/' || c == '\\' || c == ':' || c == ']')
first = ptr;
while ((c = *first++) != EOS && c != '.' && --n > 0)
*result++ = c;
*result = EOS;
}
#ifdef FILEBASED
void
readarray(array,n) /* read array from savefile */
int *array,n;
{
RINT i;
for (i=1; i<=n; i++)
fscanf(savefile,"%d ",array+i);
}
void
writearray(array,n) /* write array to savefile */
int *array,n;
{
RINT i;
for (i=1; i<=n; i++)
fprintf(savefile,"%d%c",array[i],(i%10)?' ':'\n');
if (n%10) putc('\n',savefile);
}
#endif
static void
randset()
/*
* Set up random number generator, taking care that different players
* starting at the same second, and file players on successive steps,
* will have different seeds.
*/
{
#ifndef THINKC3
time_t time();
#endif
double drand();
int seed,i;
seed = (int) (time((time_t *)0)&32767);
seed ^= (id*1319 ^ (id&3)*9929 ^ role*10343 ^ (t&15)*1933 ^ mtype*977);
#ifdef ANSI
srand((unsigned int) (seed&RAND_MAX));
#else
srand(seed&RAND_MAX);
#endif
for (i=0; i<13; i++)
drand(); /* exercise it */
}
double
drand()
/*
* Uniform [0,1) random number generator, for use by user's strategies.
*/
{ return ((double) rand())/(((double) RAND_MAX) + 1.0); }
void
error(msg) /* routine for unexpected fatal error */
char * msg;
{
char myname[7];
char *ptr;
if (noblock)
resetterm();
if (*msg != EOS) {
ptr = (*msg=='*')? msg+1: msg;
if (id>0 && (role==1 || role==2))
sprintf(myname," (%c%d)",(role==1)?'B':'S',id);
else
myname[0] = EOS;
fprintf(stderr,"\n*** error in '%s'%s: %s\n",
progname,myname,ptr);
}
#ifdef DISPLAY_OR_INET
if (gameid > 0)
fprintf(stderr,"Exit from game %d\n",gameid);
#endif
if (*msg != '*')
sendmess(QUIT,*msg==EOS?0:1);
adios(*msg==EOS?GOODEXIT:BADEXIT,1,*msg=='*');
}
static void
adios(status,delin,delout)
int status,delin,delout;
/*
* Routine for all exits. Restores terminal, deletes .in and/or .out file
* as requested, exits with status.
*/
{
if (noblock)
resetterm();
#ifdef THINKC
if (status != GOODEXIT || waitforreturn) {
printf("------- Press Return to Continue -------\n");
getchar();
}
#endif
#ifdef FILEBASED
if (infile!=NULL) fclose(infile);
if (outfile!=NULL) fclose(outfile);
#ifdef ALWAYSDELIN
delin = 1;
#endif
if (delout) REMOVE(outname);
if (delin) REMOVE(inname);
#endif
exit(status);
}
void header()
{
printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
printf(" ############################################\n");
printf(" # Santa Fe Double Auction #=\n");
printf(" ############################################=-\n");
printf(" # UNIX Version 1.0 #=-.\n");
printf(" # TCP/IP required #=-.\n");
printf(" # #=-.\n");
printf(" # 1992 #=-.\n");
printf(" # Santa Fe Institute #=-.\n");
printf(" # Economic Science Laboratory #=-.\n");
printf(" # National Science Foundation #=-.\n");
printf(" ############################################=-.\n");
printf(" ============================================-.\n");
printf(" --------------------------------------------.\n");
printf(" ............................................\n");
} /* header */
void get_gamedata(fddad)
int fddad;
{
char string[200];
int a,b,c,d,e;
if(sock_gets(fddad,string,200) == -1)
error("connection broken while reading gamedata");
sscanf(string,"%f %f %d %d %d %d %d %d\n", &payment_base,
&payment_rate, &a, &b, &c, &d, &e, &clearingrule);
rantok_main(a,b,c,d,e);
if(a == 0) havegametype = 0; /* FALSE */
else havegametype = 1; /* TRUE */
} /* get_gamedata */
void get_gamehist(fddad)
int fddad;
{
FILE *fp;
char string[200];
int empties = 0;
if((fp = fopen("gamehist.dat","w")) == NULL)
error("couldn't open gaemhist.dat for writing");
while(0==0)
{
if(sock_gets(fddad,string,200) < 0)
error("connection broken while reading gamedata");
if(strncmp(string,"end",3) == 0 ) {
fclose(fp);
return;
} else {
fprintf(fp,"%s\n",string);
}
if(strlen(string) == 0) {
sleep(1);
empties++;
if(empties>50) {
fclose(fp);
return;
}
}
} /* while */
} /* get_gamehist */
void get_players(fddad)
int fddad;
{
FILE *fp;
char string[200];
int empties = 0;
if((fp = fopen("players.dat","w")) == NULL)
error("couldn't open gaemhist.dat for writing");
while(0==0)
{
if(sock_gets(fddad,string,200) < 0)
error("connection broken while reading gamedata");
if(strncmp(string,"end",3) == 0 ) {
fclose(fp);
return;
} else {
fprintf(fp,"%s\n",string);
}
if(strlen(string) == 0) {
sleep(1);
empties++;
if(empties>50) {
fclose(fp);
return;
}
}
} /* while */
} /* get_players */
static void
sleep(secs)
int secs;
{
long start,end,ltime;
start = time(<ime);
end = start + secs;
do {;} while(time(<ime)<end);
}
int sock_gets(sd,buf,len)
int sd, len;
char *buf;
{
char *mptr;
int i=0;
mptr = buf;
while (read(sd,mptr,1) == 1 && *mptr != '\n' && i<len-1)
{
mptr++;
i++;
}
if (*mptr != '\n')
return -1;
*mptr = '\0';
return i;
}
void menu()
{
int choice = 0;
char reply[128];
while(choice != 7) {
print_menu();
printf("\nYour choice? ");
gets(reply);
choice = atoi(reply);
printf("\n");
switch(choice) {
case 1: /* show table of random draws */
if(!havegametype) {
printf("You are not allowed to view token information in this game.\n\n");
break;
}
intro_chart();
break;
case 2: /* show payment rates */
show_payment_rates();
break;
case 3: /* show clearing rule */
show_clearingrule();
break;
case 4: /* read descriptions of robot player strategies */
show_descriptions();
break;
case 5: /* show players.dat */
show_players();
break;
case 6: /* show gamehist.dat */
show_gamehist();
break;
case 7: /* begin session */
printf("\nBeginning session with AZTE now....\n");
break;
case 8: /* quit */
sendmess(QUIT,0);
exit(0);
default:
printf("Please choose a number between 1 and 8.\n\n\n");
} /* switch */
fflush(stdin);
} /* end while */
} /* menu */
void print_menu()
{
puts(" ");
puts(" ===============================================================");
puts(" = AZTE Menu Options: =");
puts(" ===============================================================");
puts(" = 1. Show Table of Random Value Token Draws (Supply & Demand) =");
puts(" = 2. Show Payment Rates for Today's Game =");
puts(" = 3. Display the Clearing Rule =");
puts(" = 4. Read Descriptions of Robot Player Strategies =");
puts(" = 5. Show Your Current Robot Opponents =");
puts(" = 6. Review Game History =");
puts(" = 7. Begin a Session with Arizona Token Exchange now =");
puts(" = 8. Quit and exit. =");
puts(" ===============================================================");
puts(" ");
} /* print_menu */
void show_payment_rates()
{
printf("BASE = $%.2f RATE = $%.2f\n\n",payment_base,payment_rate);
printf("In today's game you will receive a base payment of $%.2f\n",
payment_base);
printf("plus $%.2f times (your efficiency minus 100)\n",payment_rate);
printf("\n RATE * ( %% Efficiency - 100 )\n");
printf("\nPress Enter/Return to continue....\n");
waitkey();
}
void show_clearingrule()
{
char therule[20];
if(clearingrule == 0)
strcpy(therule,"RANDOM");
else
strcpy(therule,"AVERAGE");
printf("\nToday's game will use the %s clearing rule.\n", therule);
printf("\nPress Enter/Return to continue....\n");
waitkey();
}
void show_descriptions()
{
display_file("robots.txt");
printf("\n\nThis file (\"robots.txt\") can also be viewed outside the program.\n");
} /* show_descriptions */
void show_players()
{
display_file("players.dat");
}
void show_gamehist()
{
display_file("gamehist.dat");
}
void display_file(filename)
char * filename;
{
FILE *fd;
int quitnow=0,total,line=0;
char *pt, buf[130],string[128];
fd = fopen(filename,"r");
if(fd == NULL) {
printf("Could not open %s for reading.\n", filename);
printf("Press Enter/Return to return to the main menu...\n");
waitkey();
return;
}
total = line_count(fd);
if(total == 0) total = 1;
rewind(fd);
fgets(buf,128,fd);
while(!feof(fd) && !quitnow) {
for(pt = buf;*pt != '\n' && *pt; pt++);
*pt = '\0';
puts(buf);
fgets(buf,128,fd);
if(feof(fd)) break;
line++;
if(line%23 == 0) {
printf("--More--(%d%%) <Press Enter/Return to continue, Q to quit>",
line*100/total);
gets(string);
if(*string=='q'||*string=='Q') quitnow = 1;
}
}
fclose(fd);
puts(" ");
if(quitnow) return;
printf("Press Enter/Return to continue....\n");
waitkey();
} /* display_file */
int line_count(fd)
FILE * fd;
{
int count = 0;
char buf[130];
rewind(fd);
while(!feof(fd)) {
count++;
fgets(buf,128,fd);
}
return count;
} /* line_count */
void waitkey()
{
getchar();
fflush(stdin);
} /* waitkey */